#pragma once

#if defined(_WIN32)
#if defined(EXPORTING_Logging)
#define Utility_Logging_DECLSPEC __declspec (dllexport)
#else
#define Utility_Logging_DECLSPEC __declspec (dllimport)
#endif
#else  // non windows
#define Utility_Logging_DECLSPEC
#endif

#include <memory>
#include <sstream>
#include <string>
#include <vector>

namespace SG::Utility
{
    enum SGLogLevel
    {
        trace,
        debug,
        info,
        warning,
        error,
        fatal
    };

    // 单例模式的日志记录器，提供日志记录功能
    class Utility_Logging_DECLSPEC SGLogger
    {
      public:
        // 获取唯一实例
        static SGLogger& get ();

        // 使用默认配置文件名（与可执行文件同目录下的 sgl​ogger.conf）并传入工作空间
        static void initWithWorkspace (const std::string& workspace);

        // 记录不同级别的日志信息
        virtual void trace (const std::string& msg) const;
        virtual void debug (const std::string& msg) const;
        virtual void info (const std::string& msg) const;
        virtual void warning (const std::string& msg) const;
        virtual void error (const std::string& msg) const;
        virtual void fatal (const std::string& msg) const;

        static void disable ();
      private:
        SGLogger ();
        SGLogger (const SGLogger&) = delete;
        SGLogger (SGLogger&&)      = delete;

        // 创建默认的日志接收器
        static void createDefaultSink ();

        // 内部初始化接口（不对外暴露）
        static void init (const std::string& filePath);
        static void init (const std::string& filePath, const std::string& workspace);

        // 内部控制接口和 sink 组装（不对外暴露）
        static void addTextFileSink (const std::string& filePath);
        static void addTextFileSink ();
        static void addConsoleSink ();
        static void addSyslogSink (std::string const& addr, unsigned short port = 514);

        // 内存管理
      private:
        struct SGLoggerPrivate;
        std::shared_ptr<SGLoggerPrivate> imp = nullptr;

        // 当前会话的工作空间，供默认文件日志路径使用以及配置占位符替换
        static std::string s_workspace;
    };

    // 用于格式化并记录日志信息
    class Utility_Logging_DECLSPEC SGLogRecordStream : public std::ostringstream
    {
      public:
        SGLogRecordStream (const SGLogger* theLogger, SGLogLevel theLevel);
        SGLogRecordStream (const SGLogRecordStream& other);

        ~SGLogRecordStream ();

      protected:
        const SGLogger* logger;
        SGLogLevel      level;
    };

    SGLogRecordStream& operator<< (SGLogRecordStream& stream, const std::vector<std::string>& values);

}  // namespace SG::Utility

// 定义不同日志级别的记录方式
// TRACE < DEBUG < INFO < WARN < ERROR < FATAL
#define SG_LOG_TRACE(ARG) (SG::Utility::SGLogger::get ().trace (ARG));
#define SG_LOG_DEBUG(ARG) (SG::Utility::SGLogger::get ().debug (ARG));
#define SG_LOG_INFO(ARG) (SG::Utility::SGLogger::get ().info (ARG));
#define SG_LOG_WARN(ARG) (SG::Utility::SGLogger::get ().warning (ARG));
#define SG_LOG_ERROR(ARG) (SG::Utility::SGLogger::get ().error (ARG));
#define SG_LOG_FATAL(ARG) (SG::Utility::SGLogger::get ().fatal (ARG));

// 简化日志记录方式
#define SGTrace SG::Utility::SGLogRecordStream (&SG::Utility::SGLogger::get (), SG::Utility::trace)
#define SGDebug SG::Utility::SGLogRecordStream (&SG::Utility::SGLogger::get (), SG::Utility::debug)
#define SGInfo SG::Utility::SGLogRecordStream (&SG::Utility::SGLogger::get (), SG::Utility::info)
#define SGWarn SG::Utility::SGLogRecordStream (&SG::Utility::SGLogger::get (), SG::Utility::warning)
#define SGError SG::Utility::SGLogRecordStream (&SG::Utility::SGLogger::get (), SG::Utility::error) << __FILE__ << ":" << __LINE__ << " "
#define SGFatal SG::Utility::SGLogRecordStream (&SG::Utility::SGLogger::get (), SG::Utility::fatal) << __FILE__ << ":" << __LINE__ << " "